// 启动服务
const _ = require('lodash'), fs = require('fs'), net = require('net');
module.exports = (core) => {
  const loggerNet = core.getLogger('Net'),
      config = core.getConfig('server'), sockets = {};
  let messages = fs.readdirSync(core.getPath('messages'));
  let services = {}, server = net.createServer(function(socket){
    socket.id = core.randomString(6);
    socket.core = core;
    loggerNet.info('connect: ' + socket.remoteAddress + ':' + socket.remotePort + ' #' + socket.id);
    socket.on('data',function(buffer){
      socket.charging && !sockets[socket.charging] && (sockets[socket.charging] = socket);
      let data = core.analyze(buffer);
      if (data) {
        fs.writeFileSync(core.getRealPath(`data/0x${data.command.toString('hex')}.txt`), buffer);
        messages = fs.readdirSync(core.getPath('messages'));
        if (_.includes(messages, `0x${data.command.toString('hex')}.js`)) {
          const script = core.getPath(`messages/0x${data.command.toString('hex')}.js`);
          delete require.cache[require.resolve(script)];
          require(script).run(data, core, socket, core.getLogger(`0x${data.command.toString('hex')}`));
        }
      }
    });
    //客户端关闭事件
    socket.on('close',function(data){
      loggerNet.info('close: ' +  socket.remoteAddress + ' ' + socket.remotePort + ' #' + socket.id);
    });
    // 发送回包命令
    socket.sendCommands = function(command, data) {
      const flag = new Buffer.from('faf5', 'hex');
      const version = new Buffer.from('80', 'hex');
      let length = Buffer.alloc(1);
      length.writeUInt8(data.length + 4);
      let serial = Buffer.alloc(1);
      serial.writeUInt8((new Date() - 0) % 255);
      let cmd = new Buffer.alloc(1);
      cmd.writeUInt8(command);
      const checksum = core.getCheckSum(Buffer.concat([cmd, data], cmd.length + data.length));
      const resp =  core.concat([flag, length, version, serial, cmd, data, checksum]);
      socket.write(resp);
    };
  });

  // 启动服务
  let funcRun = function() {
    let port = config.port || 9080;
    let host = config.host || null;
    server.listen(port, host, () => {
      loggerNet.info('服务已启动, 地址: ' + host + ':' + port);
      let subscriber = core.getService('redis').getSubscriber();
      subscriber.subscribe('command');
      subscriber.on('message', (channel, message) => {
        if (channel == 'command') {
          const data = JSON.parse(message);
          // 对应的充电桩进行响应
          if (sockets[data.charging]) {
            const script = core.getPath(`commands/${data.code}.js`);
            require(script).send(sockets[data.charging], data, core);
          }
        }
      });
    });
  };
  // 加载服务
  var funcLoadService = function(servicesList, callback) {
    // load service
    var serviceName = servicesList.shift();
    if (!serviceName) {
      return setImmediate(callback);
    }

    // 初始化服务
    new Promise((resolve) => {
      const file = `${core.getRootPath()}/services/${serviceName}.js`;
      loggerNet.info(`加载 ${serviceName} 服务`)
      // 判断文件是否存在
      if (!fs.existsSync(file)) {
        throw new Error(`${file} is not exist`);
      }
      var service = services[serviceName] = require(file);
      if (typeof service.init === 'function') {
        const result = service.init(serviceName, core);
        delete service.init;
        if (result instanceof Promise) {
          return resolve(result);
        }
      }
      resolve()
    }).then(() => setImmediate(() => funcLoadService(servicesList, callback))).catch((error) => {
      loggerNet.fatal('服务 [' + serviceName + '] 加载失败');
      (core.getErrorHandler())(error, 'fatal');
    })
  };
  // 加载服务
  funcLoadService(core.getConfig('services'), () => {
    funcRun();
  });
  // 暴露服务的方法
  return {
      // 关闭服务
    close: (callback) => {
      _.each(services, function(service) {
        if (typeof service.uninit === 'function') {
          service.uninit();
        }
      });
      services = {};
      server && server.close();
    },
    /* 获取服务 */
    getService: (service) => {
      return services[service] !== undefined ? services[service] : false;
    }
  };
}
